﻿// ------------------------------------------------------------------------------------
//      Copyright (c) 2013 uhavemyword@gmail.com. All rights reserved.
//      Created by Ben at 1/4/2013 11:44:26 AM
// ------------------------------------------------------------------------------------

namespace CP.NLayer.Models
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Runtime.Serialization;

    [DataContract(IsReference = true)]
    public abstract class DataErrorInfo : IDataErrorInfo
    {
        #region IDataErrorInfo
        [Obsolete(@"This property is not used(always return null). Call GetValidationErrors() to get error message.
                            The idea of coding validation logic within a method instead of a property is to avoid unnecessary calls")]
        public string Error
        {
            get { return null; }
        }

        public string this[string propertyName]
        {
            get { return ValidateProperty(propertyName); }
        }

        /// <summary>
        /// Gets an error message indicating what is wrong with the properties with ValidationAttribute.
        /// </summary>
        /// <returns>string.Empty if all validation properties are valid, otherwise validation errors.</returns>
        public virtual string GetValidationErrors()
        {
            var error = string.Empty;
            var properties = this.GetType().GetProperties();
            foreach (var p in properties)
            {
                if (p.GetCustomAttributes(typeof(ValidationAttribute), true).Count() > 0)
                {
                    var propertyError = this[p.Name];
                    if (!string.IsNullOrEmpty(propertyError))
                    {
                        error += propertyError + Environment.NewLine;
                    }
                }
            }
            return error.TrimEnd();
        }

        /// <summary>
        /// Validates current instance properties using Data Annotations.
        /// </summary>
        /// <param name="propertyName">This instance property to validate.</param>
        /// <returns>Relevant error string on validation failure or <see cref="System.String.Empty"/> on validation success.</returns>
        protected virtual string ValidateProperty(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                return string.Empty;
            }

            var value = this.GetType().GetProperty(propertyName).GetValue(this, null);
            var results = new List<ValidationResult>();
            var context = new ValidationContext(this, null, null) { MemberName = propertyName };
            var valid = Validator.TryValidateProperty(value, context, results);
            if (!valid)
            {
                var errors = results.Select(x => x.ErrorMessage).ToArray();
                return string.Join(Environment.NewLine, errors).TrimEnd();
            }

            return string.Empty;
        }
        #endregion
    }
}
